home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / c / tcc_misc.zip / RCLOCK.C < prev    next >
C/C++ Source or Header  |  1987-06-12  |  8KB  |  244 lines

  1. /*
  2.  * RCLOCK.C : A resident clock program ported from Microsoft C 4.00 to
  3.  *            Turbo C 1.00.  This program shows off some of the advanced
  4.  *            features of Turbo C such as interrupt handling and such.
  5.  *            It was alot (I mean ALOT) easier to write this in Turbo C
  6.  *            than Microsoft...
  7.  *
  8.  *  Written by Dean D. McCrory
  9.  *  For Turbo C 1.00
  10.  *  May 12, 1987     (I got my RT clock fixed <grin>)
  11.  *
  12.  *  Compile with:
  13.  *    tcc -N- rclock.c
  14.  *
  15.  *  The -N- switch turns stack checking off... Exemod is no longer needed
  16.  *  for this version of the clock.
  17.  */
  18.  
  19. #define LINT_ARGS
  20.  
  21. #include <dos.h>
  22.  
  23. /* function prototypes */
  24. int main (void);
  25. unsigned prgsize (void);
  26. void exit (int);
  27. void interrupt display_clock (void);
  28. void sc_putsa (int, int, char *, int);
  29.  
  30. /* Suppress some library functions to conserve space */
  31. _setargv () {}
  32. _setenvp () {}
  33.  
  34. #define IRET      0xcf     /* for iret in int d0 just in case */
  35. #define INTR      0xd0     /* interrupt for install checking */
  36. #define TIMER     0x1c     /* timer interrupt number */
  37. #define ON        1        /* value for active flag ... clock is on */
  38. #define CONSTANT  2        /* value for active flag ... clock is constant */
  39. #define OK        0        /* errorlevel value, installed ok */
  40. #define NOTOK     1        /* errorlevel value, not installed ok */
  41. #define SCREEN    (char far *) 0xb8000000L
  42.  
  43. /*
  44.  * Structure definition for the clock configuration... This could be modified
  45.  * by another program to modify the operation of this isr.
  46.  */
  47. struct s_clock_config
  48.    {
  49.    char iret;           /* filled with IRET instruction */
  50.    long far * sign_str; /* pointer to long containing 'clok' */
  51.    int active_fl;       /* is rclock active - default yes */
  52.    int old_second;      /* last last second in timer tick isr */
  53.    int row;             /* row of clock display */
  54.    int col;             /* column of clock display */
  55.    int attr;            /* attribute of clock display */
  56.    };
  57.  
  58. /*
  59.  * This is the default structure of the current clock configuration this
  60.  * structure will be pointed at by interrupt D0 so this program can
  61.  * determine if it is already loaded.
  62.  
  63.  * Note the insertion of an IRET instruction right before the rest of the
  64.  * structure.  If someone should call interrupt D0 it will just do a return
  65.  * from interrupt which is better than having the processor execute the
  66.  * data inside this structure.  Also, the reason this info is put in a
  67.  * structure and tied to an unused (hopefully) interrupt is so that another
  68.  * program such as a clock control program could find this structure and
  69.  * change the row, column, attribute, etc.
  70.  */
  71. struct s_clock_config clock_config =
  72.    {
  73.    IRET, (long far *) "clok", ON, 99, 0, 68, 7
  74.    };
  75.  
  76. /*
  77.  * Below is a far pointer initialized to the BIOS clock tick count
  78.  */
  79. long far * clock_count = (long far *) 0x0000046cL;
  80.  
  81. /*
  82.  * Pointer to old timer interrupt service routine
  83.  */
  84. void interrupt (*old_timer) ();
  85.  
  86. /*  main ()
  87.  *
  88.  *  Check to see if our code is already installed and if not install it.
  89.  *  A message saying that the code is already installed is not printed for
  90.  *  memory space reasons.  As far as I know there is no way to only make
  91.  *  part of a program resident and dump the install code (There is in
  92.  *  assembler but not in higher level languages).  It does return a code in
  93.  *  errorlevel indicating the success or failure of the install.
  94.  */
  95. int main ()
  96. {
  97.    struct s_clock_config far * config_ptr;
  98.  
  99.    /*
  100.     * set a temporary pointer to be used to access structure more easily
  101.     */
  102.    config_ptr = (struct s_clock_config far *) getvect (INTR);
  103.  
  104.    /*
  105.     * check to see if the code is already resident by checking interrupt
  106.     */
  107.    if (*config_ptr->sign_str != *clock_config.sign_str)
  108.       {
  109.       /* Not resident, install resident code, and set interrupt D0 so we can
  110.        * tell that rclock is resident.
  111.        */
  112.       old_timer = getvect (TIMER);      /* save old vector */
  113.       setvect (TIMER, display_clock);   /* set to ours */
  114.       setvect (INTR, (void interrupt (*) ()) &clock_config);
  115.       keep (OK, prgsize ());            /* terminate and stay resident */
  116.       }
  117.  
  118.    return (NOTOK);                     /* already installed */
  119. }
  120.  
  121. /* prgsize ()
  122.  *
  123.  * Calculates the program size by looking at __brklvl which is set to
  124.  * the end of initialized and uninitialized data whithin the data segment
  125.  * at program startup.  __brklvl is then changed as memory space is
  126.  * malloc'd.  __brklvl is decremented as malloc'd areas are free'd.
  127.  *
  128.  *   ** This function should work in Tiny, Small, and Meduim models **
  129.  */
  130.  
  131. unsigned prgsize ()
  132. {
  133.    extern unsigned __brklvl;     /* current top of heap == sbrk (0) */
  134.    extern unsigned _psp;         /* lowest segment address occupied */
  135.  
  136.    return (_DS + (__brklvl + 15) / 16 - _psp);
  137. }
  138.  
  139. /* exit ()
  140.  *
  141.  * Rewrite exit for memory conservation.  This exit () does not close files
  142.  * or flush buffers, which is fine in this case because we have no open
  143.  * files or buffers which need to be flushed.
  144.  *
  145.  */
  146. void exit (status)
  147.    int status;
  148. {
  149.    _exit (status);
  150. }
  151.  
  152. /* display_clock ()
  153.  *
  154.  * Timer ISR, displays the clock on screen if the second has changed and
  155.  * the clock active flag is 1 or the clock active flag is 2 (constant mode).
  156.  */
  157. void interrupt display_clock ()
  158. {
  159.    int hour;               /* temporary for hour */
  160.    int minute;             /* temporary for minute */
  161.    int second;             /* temporary for second */
  162.    long remain;            /* temporary for remainder during divides */
  163.    static int in_fl = 0;   /* are we already in this ISR */
  164.    static char time_string[9] = "  :    m";
  165.  
  166.    /* Chain to the old timer routine */
  167.    (*old_timer) ();
  168.    
  169.    /* Make sure we do not enter our code recursively */
  170.    if (in_fl)
  171.       return;
  172.  
  173.    in_fl = 1;
  174.  
  175.    /* The following formula was taken from Peter Nortons Programmer's Guide
  176.       to the IBM-PC... there is a bug in it which momentarily (half second)
  177.       assigns the minute to 60 just before changing hours */
  178.    remain = *clock_count;
  179.    hour = remain / 65543L;
  180.    remain %= 65543L;
  181.    minute = remain / 1092;
  182.    remain %= 1092;
  183.    second = remain * 100 / 1821;
  184.  
  185.    if (clock_config.active_fl && second != clock_config.old_second)
  186.       {
  187.       /* The clock is active and the second is different, rebuild the
  188.          clock string */
  189.       time_string[2] = time_string[2] == ':' ? ' ' : ':'; 
  190.       time_string[6] = hour >= 12 ? 'p' : 'a';
  191.  
  192.       /* convert the hour into normal 12 hour system */
  193.       if (hour == 0)
  194.          hour = 12;
  195.       else
  196.          if (hour > 12)
  197.             hour -= 12;
  198.  
  199.       *time_string = hour / 10 + '0';
  200.       *(time_string+1) = hour % 10 + '0';
  201.       *(time_string+3) = minute / 10 + '0';
  202.       *(time_string+4) = minute % 10 + '0';
  203.       }
  204.  
  205.    if ((clock_config.active_fl == ON && second != clock_config.old_second) ||
  206.       clock_config.active_fl == CONSTANT)
  207.       {
  208.       /*
  209.        * Save the old second and write the clock string to the correct
  210.        * screen position.
  211.        */
  212.       clock_config.old_second = second;
  213.       sc_putsa (clock_config.row, clock_config.col, time_string,
  214.          clock_config.attr);
  215.       }
  216.  
  217.    in_fl = 0;     /* we are now ready to exit our isr so indicate so */
  218. }
  219.  
  220. /* sc_putsa ()
  221.  *
  222.  * Print a string with the given attribute and row and column directly to
  223.  * color screen RAM.  Note that this will produce "snow" on CGA systems.
  224.  */
  225. void sc_putsa (row, col, string, attr)
  226.    int row;
  227.    int col;
  228.    register char * string;
  229.    int attr;
  230. {
  231.    register char far * ptr;         /* will be pointer into screen RAM */
  232.  
  233.    /* calculate pointer to screen RAM */
  234.    ptr = SCREEN + row * 160 + col * 2;
  235.  
  236.    /* write each of the characters in string to the screen RAM */
  237.    while (*string)
  238.       {
  239.       *ptr++ = *string++;           /* write the character */
  240.       *ptr++ = attr;                /* write the attribute */
  241.       }
  242. }
  243.  
  244.